#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ogcsys.h>
#include <network.h>

/* Constants */
#define NETWORK_HOSTNAME	"acies.googlecode.com"
#define NETWORK_PATH		"/files/"
#define NETWORK_PORT		80

/* Host IP */
static char hostip[16] ATTRIBUTE_ALIGN(32);

/* Network variables */
static s32 sockfd = -1;


char *network_getip(void)
{
	/* Return IP string */
	return hostip;
}

s32 network_init(void)
{
	s32 ret;

	/* Initialize network */
	ret = if_config(hostip, NULL, NULL, true);
	if (ret < 0)
		return ret;

	return 0;
}

s32 network_connect(void)
{
	struct hostent *he;
	struct sockaddr_in sa;

	s32 ret;

	/* Close socket if it is already open */
	if (sockfd >= 0)
		net_close(sockfd);

	/* Create socket */
	sockfd = net_socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
	if (sockfd < 0)
		return sockfd;

	/* Get host by name */
	he = net_gethostbyname(NETWORK_HOSTNAME);
	if (!he)
		return -1;

	/* Setup socket */
	memcpy(&sa.sin_addr, he->h_addr_list[0], he->h_length);
	sa.sin_family = AF_INET;
	sa.sin_port = htons(NETWORK_PORT);

	ret = net_connect(sockfd, (struct sockaddr *)&sa, sizeof(sa));
	if (ret < 0)
		return ret;

	return 0;
}

s32 network_request(const char *filepath)
{
	char buf[1024], request[256];
	char *ptr = NULL;

	u32 cnt, size;
	s32 ret;

	/* Generate HTTP request */
	sprintf(request, "GET " NETWORK_PATH "%s HTTP/1.1\r\nHost: " NETWORK_HOSTNAME "\r\nConnection: close\r\n\r\n", filepath);

	/* Connect to server */
	ret = network_connect();
	if (ret < 0)
		return ret;

	/* Send request */
	ret = net_send(sockfd, request, strlen(request), 0);
	if (ret < 0)
		return ret;

	/* Clear buffer */
	memset(buf, 0, sizeof(buf));

	/* Read HTTP header */
	for (cnt = 0; !strstr(buf, "\r\n\r\n"); cnt++)
		if (net_recv(sockfd, buf + cnt, 1, 0) <= 0)
			return -1;

	/* HTTP request OK? */
	if (!strstr(buf, "HTTP/1.1 200 OK"))
		return -1;
	/* Retrieve content size */
	ptr = strstr(buf, "Content-Length:");
	if (!ptr)
		return -1;

	sscanf(ptr, "Content-Length: %u", &size);
	return size;
}

s32 network_read(void *buf, u32 len)
{
	s32 read = 0, ret;

	/* Data to be read */
	while (read < len) {
		/* Read network data */
		ret = net_read(sockfd, buf + read, len - read);
		if (ret < 0)
			return ret;

		/* Read finished */
		if (!ret)
			break;

		/* Increment read variable */
		read += ret;
	}

	return read;
}

s32 network_write(void *buf, u32 len)
{
	s32 ret, written;

	/* Write network data */
	ret = net_write(sockfd, buf, len);
	if (ret <= 0)
		return ret;

	/* Check if there's data to be written */
	if (ret < len) {
		written = network_write(buf + ret, len - ret);
		if (written < 0)
			return written;

		ret += written;
	}

	return ret;
}
